package com.zxh.audio;

import javax.sound.sampled.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;

/**
 * Created by zhangxh on 2016/7/12.
 */
public class MyRecord {
    private MyRecord(){}
    private static boolean isRecording=false;

    private static TargetDataLine td = null;
    private static DataLine.Info info = null;
    private static AudioFormat audioFormat=new AudioFormat(
            AudioFormat.Encoding.PCM_SIGNED,
            16000f, //44.1 kHz sampling rate = CD quality audio
            16, //1 bytes, 8 bit audio (1 * 8 bit byte)
            1, //1 channels, stereo
            2, //frame size = number of bytes in a sample * number of channels = Default WAVE
            16000f, //frame rate = sampling rate = Default WAVE
            false //little endian = Default WAVE
    );
    /*private static AudioFormat audioFormat=new AudioFormat(
            AudioFormat.Encoding.PCM_SIGNED,
            16000f, //44.1 kHz sampling rate = CD quality audio
            16, //1 bytes, 8 bit audio (1 * 8 bit byte)
            1, //1 channels, stereo
            2, //frame size = number of bytes in a sample * number of channels = Default WAVE
            16000f, //frame rate = sampling rate = Default WAVE
            true //little endian = Default WAVE
    );*/

    private static AudioInputStream audioInputStream = null;

    public static void setAudioFormat(AudioFormat format){
        audioFormat=format;
    }
    public static void open(){
        if (null == info) {
            info = new DataLine.Info(TargetDataLine.class, audioFormat);
        }
        // 获取录音设备
        try {
            if(null==td){
                td = (TargetDataLine) (AudioSystem.getLine(info));
            }
            if(!td.isOpen()){
                // 打开具有指定格式的行，这样可使行获得所有所需的系统资源并变得可操作。
                td.open(audioFormat,td.getBufferSize());
            }
            if(!td.isRunning()){
                // 允许某一数据行执行数据 I/O
                td.start();
            }
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
    }

    public static void start(){
        if(isRecording){
            return;
        }else{
            isRecording=true;
        }
        new Thread(new Runnable() {
            public void run() {
                try {
                    //create a new output stream. When we read from the Line, well write the
                    //data to this output stream
                    ByteArrayOutputStream out = new ByteArrayOutputStream();
                    //calculate the length of the buffer to use for recording
                    int frameSizeInBytes = audioFormat.getFrameSize();
                    int bufferLengthInFrames = td.getBufferSize() / 8;
                    int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
                    //create the buffer
                    byte[] data = new byte[bufferLengthInBytes];
                    int numBytesRead;

                    while (isRecording) {
                        //read the data into the byte[]
                        if ((numBytesRead = td.read(data, 0, bufferLengthInBytes)) == -1) {
                            //if there is an error, stop recording
                            break;
                        } else {//write the data out to the byte array and do it all again
                            out.write(data, 0, numBytesRead);
                        }
                    }
                    // Recording complete. Stop and close the line.
                    td.stop();
                    td.close();
                    td = null;

                    // Now, stop and close the output stream
                    out.flush();
                    out.close();

                    //get the byte[] from the output stream
                    byte audioBytes[] = out.toByteArray();
                    //create an input stream
                    ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);
                    //request an AudioInputStream from the AudioSystem
                    audioInputStream = new AudioInputStream(bais, audioFormat, audioBytes.length / frameSizeInBytes);
                    //reset the AudioInputStream, sets the current frame postion to the beginning
                    audioInputStream.reset();
                } catch (Exception e) {
                    e.printStackTrace();
                    isRecording=false;
                }
            }
        }).start();


    }
    public static void stop(){
        isRecording=false;
    }

    public static boolean saveToFile(File file, AudioFileFormat.Type fileType) throws Exception {
        if(isRecording){
            return  false;
        }
        if(audioInputStream==null){
            return false;
        }
        audioInputStream.reset();
        return (AudioSystem.write(audioInputStream, fileType, file) == -1);
    }
}
